/*
 * Parser.h
 */

#ifndef PARSER_H_
#define PARSER_H_

#include <fstream>
#include <stdio.h>
#include <string>
#include "TablaDefiniciones.h"
#include "./TiposComunes.h"

#define INI_COMENT_LARGO "/*"
#define LONG_INI_COMENT_LARGO std::string(INI_COMENT_LARGO).size()
#define FIN_COMENT_LARGO "*/"
#define LONG_FIN_COMENT_LARGO std::string(FIN_COMENT_LARGO).size()
#define INI_COMENT_LINEA "//"
#define CHR_DIRECT_PRECOMP '#'
#define SEP_PALABRAS "*+-/%<;>,= \n"

class Parser {
private:
	// Verdadero si se trabaja desde disco, falso si se tiene el archivo en mem
	bool modoAccesoDisco;

	// Permiten trabajar con la totalidad del archivo en memoria
	std::string archivoCompleto;
	size_t tamArchivoCompleto;
	size_t pLectArchComp;

	// Permite trabajar con archivos de disco
	std::ifstream archivo;

	/** Lee la sgte linea del disco o de memoria según corresponda.
	 * @param lineaLeida Cadena donde carga la linea leida.
	 * @return Verdadero si se cargo o falso si no hay más para leer.
	 */
	bool leerLinea(std::string &lineaLeida);

	/** Quita los comentarios de la linea. Si son multilinea, continua
	 * leyendo hasta encontrar fin de comentario.
	 * @param lineaLeida Cadena donde devuelve la linea sin comentarios.
	 * @return Verdadero si se cargo o falso si hay problemas de sintaxis.
	 */
	bool quitarComentarios(std::string &lineaLeida);
public:
	/** Crea un parser para trabajar un archivo ya cargado en memoria.
	 * @param archivoCargado Cadena con el archivo completo cargado.
	 */
	Parser(const std::string &archivoCargado);

	/** Crea un parser para trabajar con un archivo en disco.
	 * @param ruta Directorio al archivo a abrir
	 * @param nombre Nombre y extension del archivo a abrir
	 */
	Parser(const std::string &ruta, const std::string &nombre);

	virtual ~Parser();

	/** Evalua las condiciones del parser para empezar a operar.
	 * @return Verdadero si el archivo de entrada está abierto o el archivo en
	 * la cadena pasada no esta vacio.
	 */
	bool estadoValido() const;

	/** Carga la siguiente linea del archivo en lineaLeida, sin comentarios
	 * @param lineaLeida Cadena donde se cargara la linea leida
	 * @return Verdadero si se cargo la linea o falso si hubo un error
	 */
	bool parsearLinea(std::string &lineaLeida);

	/** Analiza si la linea leida es directiva de precompilador
	 * @param lineaLeida Cadena a analizar si es directiva de precompilador
	 * @return Verdadero si la cadena es directiva, falso en caso contrario
	 */
	bool esDirectiva(const std::string &lineaLeida) const;

	/** Devuelve el comando de una linea ya identificada como directiva.
	 * @param lineaLeida Linea de donde extraer la directiva del precompilador
	 * @return Directiva extraida o cadena vacia
	 */
	std::string getDirectiva(const std::string &lineaLeida) const;

	/** Devuelve los arguementos de una directiva ya identificada.
	 * @param lineaLeida Linea de donde extraer el valor de la directiva
	 * @return Valor de directiva extraido o cadena vacia
	 */
	std::string getValorDirectiva(const std::string &lineaLeida) const;

	/** Extrae el contenido entre los dos primeros tokens.
	 * @param cadena Cadena de donde extraer el valor a tokenizar.
	 * @return Valor extraido o cadena vacia si falta algún token
	 */
	std::string tokenizarDobleLado(const std::string &cadena,
			const std::string &token) const;

	/** Busca en la tabla de definiciones y hace los reemplazos en el buffer
	 * @param bufferLectura Cadena a analizar y realizar los reemplazos
	 * @param tabDef Referencia a tabla de definiciones
	 */
	void reemplazarDefiniciones(std::string &bufferLectura,
			const TablaDefiniciones &tabDef) const;

};

#endif /* PARSER_H_ */
